﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace WindowsFormsApplication1
{
    public class tcpstuff
    {
        //Socket creation, regular UDP socket

        public Socket UDPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        public string Target_IP = "224.10.10.10";
        public int Target_Port = 31337;
        public String data_received="";
        byte[] byteData = new byte[1024];

        public String get_data_receive()
        {
            return data_received;
        }

        //socket initialization

        public tcpstuff()
        {
            //nothing should go wrong in here
            try
            {
                //recieve data from any source
                IPEndPoint LocalHostIPEnd = new IPEndPoint(IPAddress.Any, Target_Port);

                //init Socket
                UDPSocket.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.NoDelay, 1);

                //allow for loopback testing
                UDPSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);

                //extremly important to bind the Socket before joining multicast groups
                UDPSocket.Bind(LocalHostIPEnd);


                UDPSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 0);

                //join multicast group
                UDPSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse(Target_IP)));

                //get in waiting mode for data - always (this doesn't halt code execution)
                Recieve();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message + "" + e.StackTrace);
            }
        }



        //client send function
        public void Send(string sendData)
        {
            byte[] bytesToSend = Encoding.ASCII.GetBytes(sendData);

            //set the target IP
            IPEndPoint RemoteIPEndPoint = new IPEndPoint(IPAddress.Parse(Target_IP), Target_Port);
            EndPoint RemoteEndPoint = (EndPoint)RemoteIPEndPoint;

            //do asynchronous send
            UDPSocket.BeginSendTo(bytesToSend, 0, bytesToSend.Length, SocketFlags.None, RemoteEndPoint, new AsyncCallback(SendCallback), UDPSocket);
        }

        //executes the asynchronous send
        public void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket client = (Socket)ar.AsyncState;

                // Complete sending the data to the remote device.
                int bytesSent = client.EndSendTo(ar);

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }


        //initial receive function - called only once
        public void Recieve()
        {
            try
            {
                IPEndPoint LocalIPEndPoint = new IPEndPoint(IPAddress.Any, Target_Port);
                EndPoint LocalEndPoint = (EndPoint)LocalIPEndPoint;

                // Create the data
                data_received = "Player2 score is 0";
                // Begin receiving the data from the remote device.
                UDPSocket.BeginReceiveFrom(byteData, 0, byteData.Length, 0, ref LocalEndPoint,
                new AsyncCallback(ReceiveCallback), LocalEndPoint);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        //executes the asynchronous receive - executed everytime data is received on the port
        public void ReceiveCallback(IAsyncResult ar)
        {
            try
            {

                IPEndPoint LocalIPEndPoint = new IPEndPoint(IPAddress.Any, Target_Port);
                EndPoint LocalEndPoint = (EndPoint)LocalIPEndPoint;

                //Transform the array of bytes received from the user into an
                //intelligent form of object Data
 

                
                // Read data from the remote device.
                int bytesRead = UDPSocket.EndReceiveFrom(ar, ref LocalEndPoint);
                data_received = Encoding.UTF8.GetString(byteData, 0, bytesRead);
                Console.WriteLine(data_received);
                //keep listening
                UDPSocket.BeginReceiveFrom(byteData, 0, byteData.Length, 0, ref LocalEndPoint,
                new AsyncCallback(ReceiveCallback), LocalEndPoint);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }

}